home *** CD-ROM | disk | FTP | other *** search
/ InterCD 1999 June / june_1999.iso / Palm / Business / TC Logger / tclogger.c < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-09  |  34.8 KB  |  1,264 lines

  1. /*************************************************************
  2.  *
  3.  * tclogger.c:  Program to help me log my time card time for
  4.  *              several different charge numbers.
  5.  *
  6.  * This program is distributed under the GNU General 
  7.  * Public License (GPL).
  8.  * See http://www.gnu.org/copyleft/gpl.html
  9.  *
  10.  * This software comes with NO warranty at all and I
  11.  * cannot be held responsible for anything it may do.
  12.  * I make no claims as to my ability to write programs.
  13.  * You have the source code, so check it out.
  14.  *
  15.  * This program was developed on a Linux/GNU system using FREE
  16.  * tools.  A special thanks to all programmers who developed
  17.  * the following tools I used:
  18.  *
  19.  *   pilot-xfer-0.9.0
  20.  *   gcc-2.7.2 cross compiler for Palm Connected Organizers
  21.  *   gdb-4.16
  22.  *   prctools-0.5.0
  23.  *   pilot-template-1.31
  24.  *   xcopilot-0.6.6
  25.  *
  26.  * Kevin Dupree
  27.  * kdupree@flash.net
  28.  *************************************************************/
  29.  
  30. #pragma pack(2)
  31.  
  32. #include <Common.h>
  33. #include <System/SysAll.h>
  34. #include <UI/UIAll.h>
  35.  
  36. #include "callback.h"
  37. #include "tclogger.h"
  38. #include "util.h"
  39.  
  40. /*************************************************************
  41.  *      Defines                                              *
  42.  *************************************************************/
  43. #define tcloggerCreator   'TCLg'
  44. /* Define the minimum OS version allowed */
  45. #define Version20    sysMakeROMVersion (2, 0, 0, 0, 0)
  46. #define Version30    sysMakeROMVersion (3, 0, 0, 0, 0)
  47. #define NUMTIMERS 7
  48.  
  49. /*************************************************************
  50.  *    Type Definitions                                     *
  51.  *************************************************************/
  52.  
  53. typedef struct {
  54.   Boolean bRunning : 1;
  55.   Long    lStartTime;
  56.   Long    lAccumTime;
  57.   Char    sDescription[ 21 ];
  58. } TimerType;
  59.  
  60. typedef enum
  61. {
  62.   HOURS,
  63.   HOURS_MIN,
  64.   SECONDS
  65. } TimerFormatType;
  66.  
  67. /* preferences state file. */
  68. typedef struct {
  69.   TimerFormatType AccumFormat;
  70.   Char sInTime[ 41 ];
  71.   Char sOutTime[ 41 ];
  72.   TimerType TimerState[ NUMTIMERS ];
  73. } TCLoggerPrefType;
  74.  
  75.  
  76. /*************************************************************
  77.  *    Global Variables                                     *
  78.  *************************************************************/
  79.  
  80. static TimerType TimerData[ NUMTIMERS ];
  81. static VoidHand hndExport;
  82. static VoidHand hndInDesc;
  83. static VoidHand hndOutDesc;
  84. static VoidHand hndTime[ NUMTIMERS ];
  85. static VoidHand hndDesc[ NUMTIMERS ];
  86. static TimerFormatType AccumFormat = HOURS;
  87. static Char sInTime[ 41 ];
  88. static Char sOutTime[ 41 ];
  89. SystemPreferencesType sysPrefs;   /* User's Pilot preferences. */
  90. static Boolean bOKBold;
  91. static VoidHand hndTotal;
  92.  
  93.  
  94. /*************************************************************
  95.  *    Routines                                             *
  96.  *************************************************************/
  97. static Word StartApplication( void );
  98. static void EventLoop( void );
  99. static Boolean ApplicationHandleEvent( EventPtr );
  100. static Boolean MainHandleEvent( EventPtr );
  101. static Boolean MenuApplicationEvent( EventPtr );
  102. static void StopApplication( void );
  103.  
  104. static void UpdateAllTimers( void );
  105. static void ToggleTimerRun( Int );
  106. static void StartTimer( Int );
  107. static void StopTimer( Int );
  108. static void UpdateTimer( Int, Boolean );
  109. static void SetTimeFldEditable( Int, Boolean );
  110. static void GetUsersTime ( Int );
  111. static void FormatTime ( Long, char * );
  112. static void FormatDate ( char * );
  113. static Boolean TxtFieldHasFocus( Boolean );
  114. static Word GetFocusID( void );
  115. static void UpdateTotalTime( Boolean );
  116.  
  117. /*************************************************************
  118.  *
  119.  * NAME:        PilotMain
  120.  *
  121.  * DESCRIPTION: This is the main entry point for the
  122.  *              application.
  123.  *
  124.  * REVISION HISTORY:
  125.  *   Name   Date       Description
  126.  *   ----   --------   -----------
  127.  *   kld    5 Nov 98   Initial Revision
  128.  *   kld    6 Feb 99   Add setting of bold flag for font
  129.  *                     of running timer.  For some reason the
  130.  *                     bold font causes a "Fatal Exception" on
  131.  *                     PalmOS 2.0 running on actual hardware but
  132.  *                     not on PalmOS 2.0 debug ROM running on an
  133.  *                     emulator, so disable it on PalmOS 2.0
  134.  *   kld    17 Feb 99  Moved bold flag to StartApplication
  135.  *
  136.  *************************************************************/
  137. DWord PilotMain( Word cmd, Ptr cmdPBP, Word launchFlags )
  138. {
  139.   short err;
  140.   Word error;
  141.   Int i;
  142.  
  143.   CALLBACK_PROLOGUE
  144.  
  145.   err = CheckRomVersion( Version20, launchFlags );
  146.   if (err) return (err);
  147.  
  148.   switch (cmd)
  149.     {
  150.     case sysAppLaunchCmdNormalLaunch:
  151.       error = StartApplication ();
  152.       if (error) return (error);
  153.  
  154.       FrmGotoForm( tcloggerFormMain );
  155.  
  156.       EventLoop();
  157.       StopApplication();
  158.       break;
  159.  
  160.     default:
  161.       break;
  162.     }
  163.  
  164.   CALLBACK_EPILOGUE
  165.   return 0;
  166. }
  167.  
  168.  
  169. /*************************************************************
  170.  *
  171.  * NAME:         StartApplication
  172.  *
  173.  * DESCRIPTION:  This routine loads the saved prefrences
  174.  *               information and initializes global variables.
  175.  *
  176.  * REVISION HISTORY:
  177.  *   Name   Date       Description
  178.  *   ----   --------   -----------
  179.  *   kld    5 Nov 98   Initial Revision
  180.  *   kld    17 Feb 99  Moved bold flag from PilotMain to here
  181.  *
  182.  *************************************************************/
  183. static Word StartApplication( void )
  184. {
  185.   Word error = 1;
  186.   TCLoggerPrefType prefs;
  187.   Int prefsVersion;
  188.   Int prefsSize;
  189.   Int i;
  190.   DWord romVersion;
  191.  
  192.   /* Get the ROM version for which PalmOS version is being used. */
  193.   FtrGet( sysFtrCreator, sysFtrNumROMVersion, &romVersion );
  194.   bOKBold = (romVersion >= Version30);
  195.     
  196.   /* Get system preferences for In/Out date/time format */
  197.   PrefGetPreferences( &sysPrefs );
  198.  
  199.   /* Read the preferences saved-state information. */
  200.   prefsSize = sizeof (TCLoggerPrefType);
  201.   prefsVersion = PrefGetAppPreferences (tcloggerCreator,
  202.                                         TCLoggerPrefID, 
  203.                                         &prefs,
  204.                                         &prefsSize,
  205.                                         true);
  206.   if (prefsVersion == TCLoggerPrefsVersionNum)
  207.     {
  208.       AccumFormat = prefs.AccumFormat;
  209.       StrCopy( sInTime, prefs.sInTime );
  210.       StrCopy( sOutTime, prefs.sOutTime );
  211.       for (i=0; i<NUMTIMERS; i++)
  212.         TimerData[i] = prefs.TimerState[i];
  213.  
  214.       error = 0;
  215.     }
  216.   /* Set to defaults if no preferences found */
  217.   else if (prefsVersion == noPreferenceFound)
  218.   {
  219.     AccumFormat = HOURS;
  220.     StrCopy( sInTime, "None" );
  221.     StrCopy( sOutTime, "None" );
  222.     for (i=0; i<NUMTIMERS; i++)
  223.       {
  224.         TimerData[i].bRunning = false;
  225.         TimerData[i].lStartTime = 0L;
  226.         TimerData[i].lAccumTime = 0L;
  227.         StrCopy( TimerData[i].sDescription,"" );
  228.       }
  229.     error = 0;
  230.   }
  231.  
  232.   hndExport = MemHandleNew( 400 );
  233.   if (hndExport == NULL) return (1);
  234.  
  235.   hndInDesc = MemHandleNew( 41 );
  236.   if (hndInDesc == NULL) return (1);
  237.   hndOutDesc = MemHandleNew( 41 );
  238.   if (hndOutDesc == NULL) return (1);
  239.  
  240.   for (i=0; i<NUMTIMERS; i++)
  241.     {
  242.       hndTime[i] = MemHandleNew( 7 );
  243.       if (hndTime[i] == NULL) return (1);
  244.       hndDesc[i] = MemHandleNew( 21 );
  245.       if (hndDesc[i] == NULL) return (1);
  246.     }
  247.  
  248.   hndTotal = MemHandleNew( 7 );
  249.   if (hndTotal == NULL) return (1);
  250.  
  251.   return (error);
  252. }
  253.  
  254.  
  255. /*************************************************************
  256.  *
  257.  * NAME:        EventLoop
  258.  *
  259.  * DESCRIPTION: This routine is the event loop for processing
  260.  *              events.
  261.  *
  262.  * REVISION HISTORY:
  263.  *   Name   Date       Description
  264.  *   ----   ---------  -----------
  265.  *   kld    29 Nov 98  Initial Revision
  266.  *
  267.  *************************************************************/
  268. static void EventLoop( void )
  269. {
  270.   Word error;
  271.   EventType event;
  272.  
  273.   do
  274.     {
  275.       // Get the next available event.
  276.       EvtGetEvent( &event, evtWaitForever );
  277.  
  278.       // Give the system a chance to handle the event.
  279.       if ( ! SysHandleEvent( &event ) )
  280.  
  281.         // Give the menu bar a chance to update and handle the event.
  282.         if ( ! MenuHandleEvent( (void *) 0, &event, &error ) )
  283.  
  284.       // Give the application a chance to handle the event.
  285.           if ( ! ApplicationHandleEvent( &event ) )
  286.     
  287.             // Let the form object provide default handling of the event.
  288.             FrmDispatchEvent( &event ); 
  289.     }
  290.  
  291.   while (event.eType != appStopEvent);
  292. }
  293.  
  294.  
  295. /*************************************************************
  296.  *
  297.  * NAME:        EventLoop
  298.  *
  299.  * DESCRIPTION: This routine is the event loop for processing
  300.  *              events.
  301.  *
  302.  * REVISION HISTORY:
  303.  *   Name   Date       Description
  304.  *   ----   ---------  -----------
  305.  *   kld    29 Nov 98  Initial Revision
  306.  *   kld    6 Feb 99   Remove bold font for OS 2.0
  307.  *   kld    17 Feb 99  Add call to update total time.
  308.  *
  309.  *************************************************************/
  310. static Boolean ApplicationHandleEvent( EventPtr pEvent )
  311. {
  312.   FormPtr pFrm;
  313.   Int      idForm;
  314.   Boolean bHandled = false;
  315.   CharPtr sBuff;
  316.   FieldPtr pFld;
  317.   Int i;
  318.   ControlPtr pCtl;
  319.   Char sID[ 10 ];
  320.  
  321.   if (pEvent->eType == frmLoadEvent)
  322.     {
  323.       // Load the form resource specified in the event then activate the form.
  324.       idForm = pEvent->data.frmLoad.formID;
  325.       pFrm = FrmInitForm( idForm );
  326.       FrmSetActiveForm( pFrm );
  327.  
  328.       /* Set the running checkbox */
  329.       for (i=0; i<NUMTIMERS; i++)
  330.         {
  331.           /* Set the Run checkbox */
  332.           pCtl = (ControlPtr) Id2Ptr( idRunCB+i );
  333.           CtlSetValue (pCtl, TimerData[i].bRunning);
  334.           SetTimeFldEditable( i, !TimerData[i].bRunning );
  335.           /* Set the timers description */
  336.           pFld = Id2Ptr( idDescFld+i );
  337.           sBuff = MemHandleLock( hndDesc[i] );
  338.           StrCopy( sBuff, TimerData[i].sDescription );
  339.           MemHandleUnlock( hndDesc[i] );
  340.           FldSetTextHandle( pFld, (Handle) hndDesc[i] );
  341.           /* If running highlite description font and 
  342.              update the time accumulated */
  343.           if (TimerData[i].bRunning && bOKBold)
  344.             FldSetFont( pFld, boldFont );
  345.           UpdateTimer( i, false );
  346.         }
  347.       UpdateTotalTime( false );
  348.  
  349.       /* Set the clock in time */
  350.       pFld = Id2Ptr( idInFld );
  351.       sBuff = MemHandleLock( hndInDesc );
  352.       StrCopy( sBuff, sInTime );
  353.       MemHandleUnlock( hndInDesc );
  354.       FldSetTextHandle ( pFld, (Handle) hndInDesc );
  355.  
  356.       /* Set the clock out time */
  357.       pFld = Id2Ptr( idOutFld );
  358.       sBuff = MemHandleLock( hndOutDesc );
  359.       StrCopy( sBuff, sOutTime );
  360.       MemHandleUnlock( hndOutDesc );
  361.       FldSetTextHandle ( pFld, (Handle) hndOutDesc );
  362.  
  363.       // Set the event handler for the form.  The handler of the currently 
  364.       // active form is called by FrmDispatchEvent each time it receives an event.
  365.       switch (idForm)
  366.         {
  367.         case tcloggerFormMain:
  368.           FrmSetEventHandler( pFrm, MainHandleEvent );
  369.           break;
  370.  
  371.         default:
  372.           StrIToA( sID, idForm );
  373.           FrmCustomAlert( UnknownFormAlert, sID, NULL, NULL );
  374.           break;
  375.         }
  376.       bHandled = true;
  377.     }
  378.  
  379.   return bHandled;
  380. }
  381.  
  382.  
  383. /*************************************************************
  384.  *
  385.  * NAME:        MainHandleEvent
  386.  *
  387.  * DESCRIPTION: This routine processes events for the main
  388.  *              form.
  389.  *
  390.  * REVISION HISTORY:
  391.  *   Name   Date       Description
  392.  *   ----   ---------  -----------
  393.  *   kld    29 Nov 98  Initial Revision
  394.  *
  395.  *************************************************************/
  396. static Boolean MainHandleEvent( EventPtr pEvent )
  397. {
  398.   Boolean bHandled = false;
  399.   FormPtr pFrm;
  400.   CharPtr sBuff;
  401.   FieldPtr pFld;
  402.   Int i;
  403.   ControlPtr pCtl;
  404.  
  405.   CALLBACK_PROLOGUE
  406.  
  407.   switch (pEvent->eType)
  408.     {
  409.     case ctlSelectEvent:
  410.       if (pEvent->data.ctlSelect.controlID == idUpdateB)
  411.         {
  412.           UpdateAllTimers();
  413.           bHandled = true;
  414.         }
  415.       else if((pEvent->data.ctlSelect.controlID >= idRunCB) &&
  416.               (pEvent->data.ctlSelect.controlID < (idRunCB+NUMTIMERS)))
  417.         {
  418.           ToggleTimerRun( pEvent->data.ctlSelect.controlID - idRunCB );
  419.           bHandled = true;
  420.         }
  421.       else if (pEvent->data.ctlSelect.controlID == idInB)
  422.         {
  423.           FormatDate( sInTime );
  424.  
  425.           pFld = Id2Ptr( idInFld );
  426.           sBuff = (CharPtr) MemHandleLock( hndInDesc );
  427.           StrCopy( sBuff, sInTime );
  428.           MemHandleUnlock( hndInDesc );
  429.           FldSetTextHandle ( pFld, (Handle) hndInDesc );
  430.           FldDrawField( pFld );
  431.           bHandled = true;
  432.         }
  433.       else if (pEvent->data.ctlSelect.controlID == idOutB)
  434.         {
  435.           FormatDate( sOutTime );
  436.  
  437.           pFld = Id2Ptr( idOutFld );
  438.           sBuff = (CharPtr) MemHandleLock( hndOutDesc );
  439.           StrCopy( sBuff, sOutTime );
  440.           MemHandleUnlock( hndOutDesc );
  441.           FldSetTextHandle ( pFld, (Handle) hndOutDesc );
  442.           FldDrawField( pFld );
  443.           bHandled = true;
  444.         }
  445.     
  446.     case frmOpenEvent:
  447.       pFrm = FrmGetActiveForm();
  448.  
  449.       FrmDrawForm( pFrm );
  450.  
  451.       bHandled = true;
  452.       break;
  453.  
  454.     case keyDownEvent:
  455.       /* Hard button pushed that did not power on the pilot */
  456.       if (ChrIsHardKey( pEvent->data.keyDown.chr ))
  457.         {
  458.           if (! (pEvent->data.keyDown.modifiers & poweredOnKeyMask))
  459.             {
  460.               /* Launch the ToDo list application.
  461.                  Done so that TCLogger could be mapped to ToDo's hardware
  462.                  button.  Pressing ToDo's  hardware button with TCLogger
  463.                  running will launch ToDo Application */
  464.               Err err;     // Why is this var needed? See <AppLaunchCmd.h>!
  465.               AppLaunchWithCommand(sysFileCToDo, 
  466.                                    sysAppLaunchCmdNormalLaunch, 
  467.                                    NULL);
  468.               bHandled = true;
  469.             }
  470.           else
  471.             {
  472.               UpdateAllTimers();
  473.               bHandled = true;
  474.             }
  475.         }
  476.  
  477.     case menuEvent:
  478.       bHandled = MenuApplicationEvent( pEvent );
  479.       break;
  480.  
  481.     default:
  482.       bHandled = false;
  483.     }
  484.  
  485.   CALLBACK_EPILOGUE
  486.  
  487.   return bHandled;
  488. }
  489.  
  490.  
  491. /*************************************************************
  492.  *
  493.  * NAME:        MenuApplicationEvent
  494.  *
  495.  * DESCRIPTION: This routine processes menu events for the
  496.  *              main form.
  497.  *
  498.  * REVISION HISTORY:
  499.  *   Name   Date       Description
  500.  *   ----   ---------  -----------
  501.  *   kld    4 Dec 98   Initial Revision
  502.  *   kld    8 Feb 99   Add check for edited time before export.
  503.  *   kld    15 Feb 99  Added total accumulated time to
  504.  *                     exported data.
  505.  *   kld    17 Feb 99  Add call to update total time.
  506.  *
  507.  *************************************************************/
  508. static Boolean MenuApplicationEvent( EventPtr pEvent )
  509. {
  510.   Boolean bHandled = false;
  511.   CharPtr sFld;
  512.   CharPtr sBuff;
  513.   Char sTime[10];
  514.   Char sDate[20];
  515.   DateTimeType dtNow;
  516.   FieldPtr pFld;
  517.   Int i;
  518.   Word wFocused;
  519.   Int iTimer;
  520.   Long lTotalTime = 0L;
  521.   Long lRound = 1L;
  522.  
  523.   if (pEvent->data.ctlSelect.controlID == idExportMenu)
  524.     {
  525.       sFld = (CharPtr) MemHandleLock( hndExport );
  526.       StrCopy( sFld, "TCLogger Time " );
  527.       TimSecondsToDateTime( TimGetSeconds(), &dtNow );
  528.       DateToAscii( dtNow.month, dtNow.day, dtNow.year, sysPrefs.longDateFormat, sDate );
  529.       StrCat( sFld, sDate );
  530.       StrCat( sFld, "\n\n" );
  531.  
  532.       /* Export Clock In Time */
  533.       sBuff = (CharPtr) MemHandleLock( hndInDesc );
  534.       StrCat( sFld, "In Time:\t\t" );
  535.       StrCat( sFld, sBuff );
  536.       StrCat( sFld, "\n\n" );
  537.       MemHandleUnlock( hndInDesc );
  538.  
  539.       if (AccumFormat == HOURS)
  540.         lRound = 360L;
  541.       else if (AccumFormat == HOURS_MIN)
  542.         lRound = 60L;
  543.  
  544.       /* Export All the non-zero timers and descriptions */
  545.       for (i=0; i<NUMTIMERS; i++)
  546.         {
  547.           if (FldDirty ( Id2Ptr( idTimeFld+i) ))
  548.             GetUsersTime( i );
  549.           if (! TimerData[i].bRunning && 
  550.               ( TimerData[i].lAccumTime > 0L ) )
  551.             {
  552.               /* Add to total, rounding is done so that fractional
  553.                  parts do not add up and cause total to appear
  554.                  too large */
  555.               lTotalTime = lTotalTime + TimerData[i].lAccumTime - 
  556.                 (TimerData[i].lAccumTime%lRound);
  557.               FormatTime( TimerData[i].lAccumTime, sTime );
  558.               StrCat( sFld, sTime );
  559.               StrCat( sFld, "\t" );
  560.               /* Get the current description */
  561.               pFld = Id2Ptr( idDescFld+i );
  562.               sBuff = MemHandleLock( hndDesc[i] );
  563.               StrCopy( TimerData[i].sDescription, sBuff );
  564.               MemHandleUnlock( hndDesc[i] );
  565.               StrCat( sFld, TimerData[i].sDescription );
  566.               StrCat( sFld, "\n" );
  567.             }
  568.         }
  569.  
  570.       /* Export the total Time Charged */
  571.       FormatTime( lTotalTime, sTime );
  572.       StrCat( sFld, sTime );
  573.       StrCat( sFld, "\tTotal Charged\n" );
  574.  
  575.       /* Export Clock Out Time */
  576.       sBuff = (CharPtr) MemHandleLock( hndOutDesc );
  577.       StrCat( sFld, "\nOut Time:\t" );
  578.       StrCat( sFld, sBuff );
  579.       StrCat( sFld, "\n" );
  580.       MemHandleUnlock( hndOutDesc );
  581.  
  582.       MemHandleUnlock( hndExport );
  583.       ExportToMemoPad( hndExport );
  584.       bHandled = true;
  585.     }
  586.   else if (pEvent->data.ctlSelect.controlID == idClearFocusMenu)
  587.     {
  588.       if ( TxtFieldHasFocus( false ) )
  589.         {
  590.           wFocused = FrmGetFocus( FrmGetActiveForm() );
  591.           wFocused = FrmGetObjectId( FrmGetActiveForm(), wFocused );
  592.           if ( wFocused >= idTimeFld &&
  593.                wFocused < ( idTimeFld + NUMTIMERS ) )
  594.             {
  595.               iTimer = wFocused - idTimeFld;
  596.             }
  597.           else if ( wFocused >= idDescFld &&
  598.                     wFocused < ( idDescFld + NUMTIMERS ) )
  599.             {
  600.               iTimer = wFocused - idDescFld;
  601.             }
  602.  
  603.           TimerData[iTimer].lStartTime = 0L;
  604.           TimerData[iTimer].lAccumTime = 0L;
  605.           UpdateTimer( iTimer, true );
  606.           UpdateTotalTime( true );
  607.         }
  608.       bHandled = true;
  609.     }
  610.   else if (pEvent->data.ctlSelect.controlID == idClearAllMenu)
  611.     {
  612.       for (i=0; i<NUMTIMERS; i++)
  613.         {
  614.           if (! TimerData[i].bRunning )
  615.             {
  616.               TimerData[i].lStartTime = 0L;
  617.               TimerData[i].lAccumTime = 0L;
  618.               UpdateTimer( i, true );
  619.             }
  620.         }
  621.       UpdateTotalTime( true );
  622.  
  623.       StrCopy( sInTime, "None" );
  624.       pFld = Id2Ptr( idInFld );
  625.       sBuff = MemHandleLock( hndInDesc );
  626.       StrCopy( sBuff, sInTime );
  627.       MemHandleUnlock( hndInDesc );
  628.       FldSetTextHandle ( pFld, (Handle) hndInDesc );
  629.       FldDrawField( pFld );
  630.  
  631.       StrCopy( sOutTime, "None" );
  632.       pFld = Id2Ptr( idOutFld );
  633.       sBuff = MemHandleLock( hndOutDesc );
  634.       StrCopy( sBuff, sOutTime );
  635.       MemHandleUnlock( hndOutDesc );
  636.       FldSetTextHandle ( pFld, (Handle) hndOutDesc );
  637.       FldDrawField( pFld );
  638.  
  639.       bHandled = true;
  640.     }
  641.   else if (pEvent->data.ctlSelect.controlID == idClearIOMenu)
  642.     {
  643.       StrCopy( sInTime, "None" );
  644.       pFld = Id2Ptr( idInFld );
  645.       sBuff = MemHandleLock( hndInDesc );
  646.       StrCopy( sBuff, sInTime );
  647.       MemHandleUnlock( hndInDesc );
  648.       FldSetTextHandle ( pFld, (Handle) hndInDesc );
  649.       FldDrawField( pFld );
  650.  
  651.       StrCopy( sOutTime, "None" );
  652.       pFld = Id2Ptr( idOutFld );
  653.       sBuff = MemHandleLock( hndOutDesc );
  654.       StrCopy( sBuff, sOutTime );
  655.       MemHandleUnlock( hndOutDesc );
  656.       FldSetTextHandle ( pFld, (Handle) hndOutDesc );
  657.       FldDrawField( pFld );
  658.  
  659.       bHandled = true;
  660.     }
  661.   else if (pEvent->data.ctlSelect.controlID == idHoursMenu)
  662.     {
  663.       AccumFormat = HOURS;
  664.       UpdateAllTimers();
  665.       bHandled = true;
  666.     }
  667.   else if (pEvent->data.ctlSelect.controlID == idHrMinMenu)
  668.     {
  669.       AccumFormat = HOURS_MIN;
  670.       UpdateAllTimers();
  671.       bHandled = true;
  672.     }
  673.   else if (pEvent->data.ctlSelect.controlID == idSecMenu)
  674.     {
  675.       AccumFormat = SECONDS;
  676.       UpdateAllTimers();
  677.       bHandled = true;
  678.     }
  679.   else if (pEvent->data.ctlSelect.controlID == idHelpMenu)
  680.     {
  681.       FrmHelp( tcloggerHelp1 );
  682.       bHandled = true;
  683.     }
  684.   else if (pEvent->data.ctlSelect.controlID == idAboutMenu)
  685.     {
  686.       FrmHelp( tcloggerAbout1 );
  687.       bHandled = true;
  688.     }
  689.   else if (pEvent->data.ctlSelect.controlID == idKeyBrdMenu)
  690.     {
  691.       /* See Keyboard.h for details */
  692.       SysKeyboardDialog( kbdDefault );
  693.       bHandled = true;
  694.     }
  695.   else if (pEvent->data.ctlSelect.controlID == idGHelpMenu)
  696.     {
  697.       /* See GraffitiReference.h for details */
  698.       SysGraffitiReferenceDialog( referenceDefault );
  699.       bHandled = true;
  700.     }
  701.   else if (pEvent->data.ctlSelect.controlID == idUndoMenu)
  702.     {
  703.       if ( TxtFieldHasFocus( true ) )
  704.         FldUndo( Id2Ptr( GetFocusID() ) );
  705.       bHandled = true;
  706.     }
  707.   else if (pEvent->data.ctlSelect.controlID == idCutMenu)
  708.     {
  709.       if ( TxtFieldHasFocus( true ) )
  710.         FldCut( Id2Ptr( GetFocusID() ) );
  711.       bHandled = true;
  712.     }
  713.   else if (pEvent->data.ctlSelect.controlID == idCopyMenu)
  714.     {
  715.       if ( TxtFieldHasFocus( true ) )
  716.         FldCopy( Id2Ptr( GetFocusID() ) );
  717.       bHandled = true;
  718.     }
  719.   else if (pEvent->data.ctlSelect.controlID == idPasteMenu)
  720.     {
  721.       if ( TxtFieldHasFocus( true ) )
  722.         FldPaste( Id2Ptr( GetFocusID() ) );
  723.       bHandled = true;
  724.     }
  725.   else if (pEvent->data.ctlSelect.controlID == idSelectMenu)
  726.     {
  727.       if ( TxtFieldHasFocus( true ) )
  728.         FldSetSelection(Id2Ptr( GetFocusID() ), 
  729.                         0,
  730.                         FldGetTextLength( Id2Ptr( GetFocusID() ) ));
  731.       bHandled = true;
  732.     }
  733.   return bHandled;
  734. }
  735.  
  736.  
  737. /*************************************************************
  738.  *
  739.  * NAME:        StopApplication
  740.  *
  741.  * DESCRIPTION: This routine saves the current state
  742.  *              of the application.
  743.  *
  744.  * REVISION HISTORY:
  745.  *   Name   Date       Description
  746.  *   ----   ---------  -----------
  747.  *   kld    5 Nov 98   Initial Revision
  748.  *   kld    29 Nov 98  Change event loop processing
  749.  *
  750.  *************************************************************/
  751. static void StopApplication( void )
  752. {
  753.   TCLoggerPrefType prefs;
  754.   Int i;
  755.   CharPtr sDesc;
  756.  
  757.   prefs.AccumFormat = AccumFormat;
  758.  
  759.   sDesc = (CharPtr) MemHandleLock( hndInDesc );
  760.   StrCopy( prefs.sInTime, sDesc );
  761.   MemHandleUnlock( hndInDesc );
  762.  
  763.   sDesc = (CharPtr) MemHandleLock( hndOutDesc );
  764.   StrCopy( prefs.sOutTime, sDesc );
  765.   MemHandleUnlock( hndOutDesc );
  766.  
  767.   for (i=0; i<NUMTIMERS; i++)
  768.     {
  769.       sDesc = MemHandleLock( hndDesc[i] );
  770.       StrCopy( TimerData[i].sDescription, sDesc );
  771.       MemHandleUnlock( hndDesc[i] );
  772.       if (FldDirty ( Id2Ptr( idTimeFld+i ) ))
  773.           GetUsersTime( i );
  774.  
  775.       prefs.TimerState[i] = TimerData[i];
  776.     }
  777.  
  778.   PrefSetAppPreferences (tcloggerCreator,
  779.                          TCLoggerPrefID,
  780.                          TCLoggerPrefsVersionNum,
  781.                          &prefs, 
  782.                          sizeof (TCLoggerPrefType),
  783.                          true);
  784.  
  785.   /* FrmCloseAllForms will send all opened forms a
  786.      frmCloseEvent. */
  787.   FrmCloseAllForms();
  788. }
  789.  
  790.  
  791. /*************************************************************
  792.  *
  793.  * NAME:        ToggleTimerRun
  794.  *
  795.  * DESCRIPTION: This routine saves the current state
  796.  *              of the application.
  797.  *
  798.  * REVISION HISTORY:
  799.  *   Name   Date       Description
  800.  *   ----   ---------  -----------
  801.  *   kld    1 Dec 98   Initial Development
  802.  *   kld    17 Feb 99  Add call to update total time.
  803.  *
  804.  *************************************************************/
  805. static void ToggleTimerRun( Int iTimer )
  806. {
  807.   if (TimerData[iTimer].bRunning)
  808.     StopTimer( iTimer );
  809.   else
  810.     StartTimer( iTimer );
  811.   TimerData[iTimer].bRunning = !TimerData[iTimer].bRunning;
  812.   SetTimeFldEditable( iTimer, !TimerData[iTimer].bRunning );
  813.  
  814.   UpdateTotalTime( true );
  815. }
  816.  
  817.  
  818. /*************************************************************
  819.  *
  820.  * NAME:        StartTimer
  821.  *
  822.  * DESCRIPTION: This routine starts the given timer.  If
  823.  *              the user has changed the accumulated time, 
  824.  *              then it is read in and used (if the format
  825.  *              is valid).
  826.  *
  827.  * REVISION HISTORY:
  828.  *   Name   Date       Description
  829.  *   ----   ---------  -----------
  830.  *   kld    1 Dec 98   Initial Development
  831.  *   kld    6 Feb 99   Remove bold font for OS 2.0
  832.  *
  833.  *************************************************************/
  834. static void StartTimer( Int iTimer )
  835. {
  836.   FieldPtr pFld = Id2Ptr( idDescFld+iTimer);
  837.  
  838.   if (FldDirty ( Id2Ptr( idTimeFld+iTimer) ))
  839.     {
  840.       GetUsersTime( iTimer );
  841.     }
  842.   TimerData[iTimer].lStartTime = TimGetSeconds();
  843.   if (bOKBold)
  844.     FldSetFont( pFld, boldFont );
  845.   FldDrawField( pFld );
  846.   UpdateTimer( iTimer, true );
  847. }
  848.  
  849.  
  850. /*************************************************************
  851.  *
  852.  * NAME:        StopTimer
  853.  *
  854.  * DESCRIPTION: This routine stops the given timer from 
  855.  *              running.
  856.  *
  857.  * REVISION HISTORY:
  858.  *   Name   Date       Description
  859.  *   ----   ---------  -----------
  860.  *   kld    1 Dec 98   Initial Development
  861.  *
  862.  *************************************************************/
  863. static void StopTimer( Int iTimer )
  864. {
  865.   FieldPtr pFld = Id2Ptr( idDescFld+iTimer);
  866.  
  867.   FldSetFont( pFld, stdFont );
  868.   FldDrawField( pFld );
  869.   UpdateTimer( iTimer, true );
  870. }
  871.  
  872.  
  873. /*************************************************************
  874.  *
  875.  * NAME:        UpdateTimer
  876.  *
  877.  * DESCRIPTION: This routine updates the displayed time.
  878.  *              If the timer is running it just displays
  879.  *              what the current accumulated time is without
  880.  *              updating global timers.
  881.  *
  882.  * REVISION HISTORY:
  883.  *   Name   Date       Description
  884.  *   ----   ---------  -----------
  885.  *   kld    1 Dec 98   Initial Development
  886.  *
  887.  *************************************************************/
  888. static void UpdateTimer( Int iTimer, Boolean bUpdateDisplay )
  889. {
  890.   Long lTime = 0L;
  891.   FieldPtr pFld;
  892.   CharPtr sFld;
  893.  
  894.   if ( TimerData[iTimer].bRunning )
  895.     {
  896.       lTime = TimGetSeconds();
  897.       TimerData[iTimer].lAccumTime = TimerData[iTimer].lAccumTime + 
  898.         (lTime - TimerData[iTimer].lStartTime);
  899.       TimerData[iTimer].lStartTime = lTime;
  900.     }
  901.   else if (FldDirty ( Id2Ptr( idTimeFld+iTimer) ))
  902.     GetUsersTime( iTimer );
  903.   lTime = TimerData[iTimer].lAccumTime;
  904.  
  905.   pFld = Id2Ptr(idTimeFld+iTimer);
  906.   sFld = (CharPtr) MemHandleLock( hndTime[iTimer] );
  907.  
  908.   FormatTime( lTime, sFld );
  909.  
  910.   MemHandleUnlock( hndTime[iTimer] );
  911.   FldSetTextHandle( pFld, (Handle) hndTime[iTimer] );
  912.   if ( bUpdateDisplay )
  913.     FldDrawField( pFld );
  914. }
  915.  
  916.  
  917. /*************************************************************
  918.  *
  919.  * NAME:        UpdateAllTimers
  920.  *
  921.  * DESCRIPTION: This routine updates all timers accumulated
  922.  *              time.
  923.  *
  924.  * REVISION HISTORY:
  925.  *   Name   Date       Description
  926.  *   ----   ---------  -----------
  927.  *   kld    1 Dec 98   Initial Development
  928.  *   kld    17 Feb 99  Add call to update total time.
  929.  *
  930.  *************************************************************/
  931. static void UpdateAllTimers( void )
  932. {
  933.   Int i;
  934.  
  935.   for (i=0; i<NUMTIMERS; i++)
  936.     {
  937.       UpdateTimer( i, true );
  938.     }
  939.   UpdateTotalTime( true );
  940. }
  941.  
  942.  
  943. /*************************************************************
  944.  *
  945.  * NAME:        SetTimeFldEditable
  946.  *
  947.  * DESCRIPTION: This routine will mark a time field as editable
  948.  *              based on the passed in value.
  949.  *
  950.  * REVISION HISTORY:
  951.  *   Name   Date       Description
  952.  *   ----   ---------  -----------
  953.  *   kld    2 Dec 98   Initial development
  954.  *
  955.  *************************************************************/
  956. static void SetTimeFldEditable( Int iTimer, Boolean bEdit )
  957. {
  958.     FieldPtr pTimeFld = Id2Ptr( idTimeFld + iTimer );
  959.     FieldAttrType attr;
  960.  
  961.     FldGetAttributes( pTimeFld, &attr );
  962.     attr.editable = bEdit;
  963.     FldSetAttributes( pTimeFld, &attr );
  964.     FldReleaseFocus( pTimeFld );
  965. }
  966.  
  967.  
  968. /*************************************************************
  969.  *
  970.  * NAME:        GetUsersTime
  971.  *
  972.  * DESCRIPTION: This routine will read in the user entered
  973.  *              time in the format H:M, H.H or SEC.  If an error
  974.  *              occurs the last saved accumulated time will be
  975.  *              restored in the time field.
  976.  *
  977.  * REVISION HISTORY:
  978.  *   Name   Date       Description
  979.  *   ----   ---------  -----------
  980.  *   kld    2 Dec 98   Initial development
  981.  *
  982.  *************************************************************/
  983. static void GetUsersTime ( Int iTimer )
  984. {
  985.   Boolean bError = false;
  986.   Boolean bHoursOnly = false;
  987.   Boolean bMinutes = false;
  988.   Int iDecimal = 1;
  989.   Long lCurrent = 0L;
  990.   Long lTime = 0L;
  991.   CharPtr pTime = FldGetTextPtr( Id2Ptr( idTimeFld + iTimer ) );
  992.   Int length = StrLen( pTime );
  993.   Int i;
  994.   Char sBuff[3];
  995.  
  996.   if (pTime)
  997.     {
  998.       for (i=0; i<length; i++)
  999.         {
  1000.           if ( *pTime >= '0' && *pTime <= '9' )
  1001.             {
  1002.               lCurrent = ( lCurrent * 10L ) + ( *pTime - '0' );
  1003.               if (bHoursOnly)
  1004.                 iDecimal*=10;
  1005.             }
  1006.           else if (*pTime == '.' && (! bHoursOnly) && (! bMinutes))
  1007.             {
  1008.               bHoursOnly = true;
  1009.             }
  1010.           else if (*pTime == ':' && (! bHoursOnly) && (! bMinutes))
  1011.             {
  1012.               bMinutes = true;
  1013.               /* Convert hours to minutes */
  1014.               lTime = lCurrent * 60L;
  1015.               lCurrent = 0L;
  1016.             }
  1017.           else if (*pTime == ' ')
  1018.             /* Skip whitespace */
  1019.             ;
  1020.           else
  1021.             bError = true;
  1022.           pTime++;
  1023.         }
  1024.       /* If there is not an error, the users time will be used
  1025.          if there is an error the old accumulated time will be
  1026.          used. */
  1027.       if (!bError)
  1028.         {
  1029.           if ( bHoursOnly )
  1030.             /* Convert hours to seconds */
  1031.             lTime = ((lCurrent * 3600L) / (Long) (iDecimal));
  1032.           else if ( bMinutes )
  1033.             /* Convert minutes to seconds */
  1034.             lTime = (lTime + lCurrent) * 60L;
  1035.           else
  1036.             lTime = lCurrent;
  1037.           TimerData[ iTimer ].lAccumTime = lTime;
  1038.         }
  1039.       else
  1040.         {
  1041.           StrIToA( sBuff, iTimer+1 );
  1042.           FrmCustomAlert( TimeParseAlert, sBuff, NULL, NULL );
  1043.         }
  1044.     }
  1045. }
  1046.  
  1047. /*************************************************************
  1048.  *
  1049.  * NAME:        ICat
  1050.  *
  1051.  * DESCRIPTION: This routine Cat the given integer to the
  1052.  *              given string
  1053.  *
  1054.  *************************************************************/
  1055. void ICat( UInt ui, char *s )
  1056. {
  1057.   Char sBuff[ 10 ];
  1058.  
  1059.   StrIToA( sBuff, ui );
  1060.   StrCat( s, sBuff );
  1061. }
  1062.  
  1063. /*************************************************************
  1064.  *
  1065.  * NAME:        FormatTime
  1066.  *
  1067.  * DESCRIPTION: This routine Cat the given integer to the
  1068.  *              given string and will pad the 10s place with
  1069.  *              0 if needed.
  1070.  *
  1071.  *************************************************************/
  1072. static void ZeroPadICat( UInt ui, char *s )
  1073. {
  1074.   if ( ui < 10 )
  1075.     {
  1076.       StrCat( s, "0" );
  1077.     }
  1078.  
  1079.   ICat( ui, s );
  1080. }
  1081.  
  1082. /*************************************************************
  1083.  *
  1084.  * NAME:        FormatTime
  1085.  *
  1086.  * DESCRIPTION: This routine will format the given time in
  1087.  *              the selected format of H.H, H:M, SEC
  1088.  *
  1089.  * REVISION HISTORY:
  1090.  *   Name   Date       Description
  1091.  *   ----   ---------  -----------
  1092.  *   kld    3 Dec 98   Initial development
  1093.  *
  1094.  *************************************************************/
  1095. static void FormatTime( Long lTime, char *sTime )
  1096. {
  1097.   UInt uiHours, uiMin, uiFrac;
  1098.  
  1099.   if (AccumFormat == HOURS)
  1100.     {
  1101.       uiHours = (UInt) (lTime / 3600L );
  1102.       lTime = (Long) ( lTime % 3600L );
  1103.       uiFrac = (UInt) (lTime / 360L );
  1104.  
  1105.       StrCopy ( sTime, "" );
  1106.       ICat( uiHours, sTime );
  1107.       StrCat( sTime, "." );
  1108.       ICat( uiFrac, sTime );
  1109.     }
  1110.   else if (AccumFormat == HOURS_MIN)
  1111.     {
  1112.       uiHours = (UInt) (lTime / 3600L );
  1113.       lTime = (Long) ( lTime % 3600L );
  1114.       uiMin = (UInt) (lTime / 60L );
  1115.  
  1116.       StrCopy ( sTime, "" );
  1117.       ICat( uiHours, sTime );
  1118.       StrCat( sTime, ":" );
  1119.       ZeroPadICat( uiMin, sTime );
  1120.     }
  1121.   else
  1122.     {
  1123.       StrIToA( sTime, (Int) lTime);
  1124.     }
  1125. }
  1126.  
  1127.  
  1128. /*************************************************************
  1129.  *
  1130.  * NAME:        FormatDate
  1131.  *
  1132.  * DESCRIPTION: This routine will format the given time for
  1133.  *              use with the clock in/out function.
  1134.  *
  1135.  * REVISION HISTORY:
  1136.  *   Name   Date       Description
  1137.  *   ----   ---------  -----------
  1138.  *   kld    3 Dec 98   Initial development
  1139.  *
  1140.  *************************************************************/
  1141. static void FormatDate ( char *sDesc )
  1142. {
  1143.   CharPtr ptrEOS;
  1144.   DateTimeType dtNow;
  1145.  
  1146.   TimSecondsToDateTime( TimGetSeconds(), &dtNow );
  1147.  
  1148.   DateToAscii( dtNow.month, dtNow.day, dtNow.year, sysPrefs.dateFormat, sDesc );
  1149.   StrCat( sDesc, " " );
  1150.   ptrEOS = sDesc + StrLen( sDesc );
  1151.   TimeToAscii( dtNow.hour, dtNow.minute, sysPrefs.timeFormat, ptrEOS );
  1152. }
  1153.  
  1154.  
  1155. /*************************************************************
  1156.  *
  1157.  * NAME:        TxtFieldHasFocus
  1158.  *
  1159.  * DESCRIPTION: This routine will determine if a text field
  1160.  *              currently has focus.
  1161.  *
  1162.  * REVISION HISTORY:
  1163.  *   Name   Date       Description
  1164.  *   ----   ---------  -----------
  1165.  *   kld    3 Dec 98   Initial development
  1166.  *
  1167.  *************************************************************/
  1168. static Boolean TxtFieldHasFocus( Boolean bCheckInOut )
  1169. {
  1170.   Word    wFocused  = FrmGetFocus( FrmGetActiveForm() );
  1171.   Boolean bIsTxtFld = 0;
  1172.  
  1173.   if ( wFocused != -1 )
  1174.     {
  1175.       wFocused  = FrmGetObjectId( FrmGetActiveForm(), wFocused );
  1176.       bIsTxtFld = ( ( wFocused >= idTimeFld &&
  1177.                       wFocused < ( idTimeFld + NUMTIMERS ) ) ||
  1178.                     ( wFocused >= idDescFld &&
  1179.                       wFocused < ( idDescFld + NUMTIMERS ) ) ||
  1180.                     ( bCheckInOut && ( wFocused == idInFld ||
  1181.                                        wFocused == idOutFld ) ) );
  1182.     }
  1183.  
  1184.   if ( !bIsTxtFld )
  1185.     {
  1186.       SndPlaySystemSound( sndError );
  1187.       FrmAlert( NoFieldSelectAlert );
  1188.     }
  1189.  
  1190.   return( bIsTxtFld );
  1191. }
  1192.  
  1193.  
  1194. /*************************************************************
  1195.  *
  1196.  * NAME:        GetFocusID
  1197.  *
  1198.  * DESCRIPTION: This routine gets the id of the frame object
  1199.  *              that currently had data entry focus.
  1200.  *
  1201.  *************************************************************/
  1202. static Word GetFocusID( void )
  1203. {
  1204.   Word wFocused = FrmGetFocus( FrmGetActiveForm() );
  1205.  
  1206.   if ( wFocused != -1 )
  1207.     {
  1208.       wFocused = FrmGetObjectId( FrmGetActiveForm(), wFocused );
  1209.     }
  1210.     
  1211.   return( wFocused );
  1212. }
  1213.  
  1214.  
  1215. /*************************************************************
  1216.  *
  1217.  * NAME:        UpdateTotalTime
  1218.  *
  1219.  * DESCRIPTION: This routine will update the total time
  1220.  *              displayed.
  1221.  *
  1222.  * REVISION HISTORY:
  1223.  *   Name   Date       Description
  1224.  *   ----   ---------  -----------
  1225.  *   kld    17 Feb 99  Initial development
  1226.  *
  1227.  *************************************************************/
  1228. static void UpdateTotalTime( Boolean bUpdateDisplay )
  1229. {
  1230.   CharPtr sFld;
  1231.   FieldPtr pFld;
  1232.   Long lTotalTime = 0L;
  1233.   Long lRound = 1L;
  1234.   Int i;
  1235.  
  1236.   if (AccumFormat == HOURS)
  1237.     lRound = 360L;
  1238.   else if (AccumFormat == HOURS_MIN)
  1239.     lRound = 60L;
  1240.  
  1241.   for (i=0; i<NUMTIMERS; i++)
  1242.     {
  1243.       if (FldDirty ( Id2Ptr( idTimeFld+i) ))
  1244.         GetUsersTime( i );
  1245.       if ( TimerData[i].lAccumTime > 0L )
  1246.         /* Add to total, rounding is done so that fractional
  1247.            parts do not add up and cause total to appear
  1248.            too large */
  1249.         lTotalTime = lTotalTime + TimerData[i].lAccumTime - 
  1250.           (TimerData[i].lAccumTime%lRound);
  1251.     }
  1252.  
  1253.   pFld = Id2Ptr( idTotalFld );
  1254.   sFld = (CharPtr) MemHandleLock( hndTotal );
  1255.  
  1256.   FormatTime( lTotalTime, sFld );
  1257.  
  1258.   MemHandleUnlock( hndTotal );
  1259.   FldSetTextHandle( pFld, (Handle) hndTotal );
  1260.  
  1261.   if ( bUpdateDisplay )
  1262.     FldDrawField( pFld );
  1263. }
  1264.